#!/usr/bin/python
# coding: UTF-8
#
# Autor Diego Pereira do Nascimento
# Testado no Sistema Operacional MacOS X 10.5.5 build 9F33 em 26/09/2008:
#  Python 2.5.2 (r252:60911, Feb 22 2008, 07:57:53) 
#  [GCC 4.0.1 (Apple Computer, Inc. build 5363)] on darwin
#
# Algumas definições:
# PIM == Plataform Independent Model
# PSM == Plataform Specific Model


import codecs
import sys
import gzip
from xml.dom.minidom import *
from converte import *


def indice(pre_psm, id):
    """Procura pelo id no pre_psm. O pre_psm é uma lista de listas, cada lista 
    possui um indice 1, o id da classe no diagrama do Dia. Quando não presente
    retorna None, caso contrário é retornada a posição da classe com id no pre_psm
    """
    for indice,valor in pre_psm.items():
        if pre_psm[indice][1] == id:
            return indice

    return None


def adicionaPaisNoPre_psm(relacionamentos, pre_psm):
    """Cria uma lista de relacionamentos entre pais e filhos e um dicionário de
    classes nomeadas no Dia, modifica o pre_psm para adicionar o pai para possibilitar 
    a ordenação na exibição das classes e substitui a classe base do filho para
    colocar o nome da classe pai
    """
    for relacionamento in relacionamentos:
        filho = indice(pre_psm, relacionamento[1])
        pai = indice(pre_psm, relacionamento[0])
        pre_psm[filho][2] = pre_psm[filho][2].replace("models.Model", pai)

        if pai not in pre_psm[filho][0]:
            pre_psm[filho][0].append(pai)

         
def parser():
    """Interpreta o XMI (PIM) do diagrama gerado pelo Dia e transforma em elementos do
    Python. Diagrama -> camada -> objeto -> Classe UML -> nome, (atributos : composição
    -> nome, tipo)
    """
    pim_objetos = pim.getElementsByTagName("dia:diagram")[0].getElementsByTagName("dia:layer")[0].getElementsByTagName("dia:object")
    pre_psm = {}
    relacionamentos = []
    imports = u""
    
    for pim_objeto in pim_objetos:
        # Procura pelas classes
        if pim_objeto.getAttribute("type") == "UML - Class":
            meuid = pim_objeto.getAttribute("id")
            for node_1 in pim_objeto.childNodes:
                if node_1.nodeType == Node.ELEMENT_NODE and node_1.hasAttributes():
                    if node_1.getAttribute("name") == "name":
                        nome_classe = node_1.getElementsByTagName("dia:string")[0].childNodes[0].data[1:-1]
                        meunome = "\nclass %s(models.Model) :\n" % nome_classe
                        pre_psm[nome_classe] = [[], meuid, meunome, 0]

                    if node_1.getAttribute("name") == "attributes":
                        for node_2 in node_1.getElementsByTagName("dia:composite"):
                            if node_2.getAttribute("type") == "umlattribute":
                                # Procura pelo tipo e nome do atributo
                                for node_3 in node_2.getElementsByTagName("dia:attribute") :
                                    if node_3.getAttribute("name") == "name":
                                         nome_atributo = node_3.getElementsByTagName("dia:string")[0].childNodes[0].data[1:-1]

                                    elif node_3.getAttribute("name") == "type":
                                        tipo_atributo = node_3.getElementsByTagName("dia:string")[0].childNodes[0].data[1:-1]

                                    elif node_3.getAttribute("name") == "value":
                                        valor_atributo = node_3.getElementsByTagName("dia:string")[0].childNodes[0].data[1:-1]
                                        if valor_atributo == '##':
                                            valor_atributo = ''

                                    elif node_3.getAttribute("name") == "visibility" and node_3.getElementsByTagName("dia:enum")[0].getAttribute("val") == "2":
                                        buscaClassesExternas(tipo_atributo)

                                converteTipos(tipo_atributo, valor_atributo, nome_atributo, pre_psm, nome_classe)

        elif pim_objeto.getAttribute("type") == "UML - Generalization":
            minhas_constantes = ['A','A']
            conexoes = pim_objeto.getElementsByTagName("dia:connection")

            for conexao in conexoes:
                if len(conexao.getAttribute("to")):
                    minhas_constantes[int(conexao.getAttribute("handle"))]=conexao.getAttribute("to")

            #print minhas_constantes

            if not 'A' in minhas_constantes:
                relacionamentos.append(minhas_constantes)

        elif pim_objeto.getAttribute("type") == "UML - SmallPackage":
            strings = pim_objeto.getElementsByTagName("dia:string")
            for string in strings:
                if len(string.childNodes[0].data[1:-1]):
                   imports += u"from %s.models import *" % (string.childNodes[0].data[1:-1])
                
    adicionaPaisNoPre_psm(relacionamentos, pre_psm)
    # Geração do código Python final (PSM)
    imprimePSM(pre_psm, imports)


def handle_uploaded_file(f):
    destination = open('diagrama.dia', 'wb+')
    for chunk in f.chunks(): # Looping over UploadedFile.chunks() instead of using read() ensures that large files don't overwhelm your system's memory.
        destination.write(chunk)
    destination.close()

   
if __name__ == '__main__':
    try:
        if len(sys.argv) == 2:
            f = codecs.open(sys.argv[1],"rb")
            # Os arquivos do Dia UML, são compactados com o gzip
            data = gzip.GzipFile(fileobj = f).read()
        else:
            print " Uso:\n \n   " + sys.argv[0] + " diagrama.dia\n\n"   

    except:   
        print "O arquivo não existe"
    # Usando o método parseString do xml.dom.minidom para a criação da variável 'pim'
    pim = parseString(data)
    parser()